#include <stdio.h>
#include <ctype.h>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include "code.h"

char CodeOpText[][100] = {
		"LABEL", "UMINUS", "ASSIGN", "ADD", "SUB", "MULT", "DIVIDE", "DIV", "MOD",
		"OR", "AND", "NOT", "LT", "LE", "GT", "GE", "EQ", "NE", "GOTO", "CALL", "APARAM",
		"FPARAM", "VAR", "RETURN", "NOOP" };

/* Quadruple : A record for intermediate code  */

	Quadruple::Quadruple() : m_op(),m_arg1(),m_arg2(),m_result() { 
		m_op = cd_NOOP;
		m_arg1=NULL;
		m_arg2=NULL;
		m_result=NULL;
	}
	CodeOp Quadruple::getOp(){ 
		return m_op; 
		}
	void Quadruple::set(CodeOp op, SymbolTableEntry* arg1, SymbolTableEntry* arg2, SymbolTableEntry* result){
		m_op = op;
		m_arg1 = arg1;	
		m_arg2 = arg2;	
		m_result = result;	
			
	}
	
	void Quadruple::print(){
		if(m_op == cd_LABEL ){
			std::cout << m_result->getLexeme() << ":";
		}else{
			std::cout << "\t\t";
			if(m_op>-1){std::cout << CodeOpText[m_op] << "\t\t";}else{std:: cout << "\t\t";}
			if(m_arg1!=NULL){std::cout << m_arg1->getLexeme() << "\t\t";}else{std:: cout << "\t\t";}
			if(m_arg2!=NULL){std::cout << m_arg2->getLexeme() << "\t\t";}else{std:: cout << "\t\t";}
			if(m_result!=NULL){std::cout << m_result->getLexeme() << "\t\t";}else{std:: cout << "\t\t";}
			std::cout << std::endl;
		}
		
		
	}


/* QuadrupleList : Linked list of quadruples */

	QuadrupleList::QuadrupleList() : m_qdr(),m_next() { m_qdr=NULL; m_next=NULL;}
	
		
	Quadruple* QuadrupleList::getQuadruple(){
		return m_qdr;
	}
	
	QuadrupleList* QuadrupleList::getNext(){
		return m_next;
	}
	
	void QuadrupleList::setNext(QuadrupleList* qdrList){
		m_next = qdrList;
	}
	
	void QuadrupleList::add(Quadruple* qdr){	// adds quadruple to list

		QuadrupleList* temp = new QuadrupleList();

		if (m_next != NULL){			
			m_next->add(qdr);
		}else{
			temp->setQuadruple(qdr);
			m_next = temp;
		}		
	}
	
	void QuadrupleList::setQuadruple(Quadruple* qdr){
		m_qdr = qdr;
	}
	
	void QuadrupleList::print(){
		if(m_qdr!=NULL){m_qdr->print();}
		if(m_next!=NULL){m_next->print();}
	}
	
	
/* Code  */
	
	Code::Code()  {
		m_qList = new QuadrupleList();
		m_tempCounter = 1;
		m_labelCounter = 1;
	}
	
	
	void Code::generate(CodeOp op, SymbolTableEntry* arg1, SymbolTableEntry* arg2, SymbolTableEntry* result){
		Quadruple* qdr = new Quadruple();
		qdr->set(op, arg1, arg2, result);		
		m_qList->add(qdr);
		//printf ("%s \n", (char*)"generate:" );
		//printf ("%s \n", result->getLexeme() );
		// todo: implimentation

	}
	
	void Code::generateCall(SymbolTableEntry* entry, EntryList* eList){
		// todo: implimentation
	}
	
	void Code::generateFormals(EntryList* eList){
		// todo: implimentation
	}
	
	void Code::generateVariables(EntryList* eList){
		// todo: implimentation
	}
	
	char* Code::newLabel(){
		std::stringstream ss;
		ss << "lab" << m_labelCounter;
		m_labelCounter++;
		char* tmpStr = new char[100];
		std::strcpy(tmpStr, ss.str().c_str());
		return tmpStr;
	}
	
	char* Code::newTemp(){
		std::stringstream ss;
		ss << "tmp" << m_tempCounter;
		m_tempCounter++;
		char* tmpStr = new char[100];
		std::strcpy(tmpStr, ss.str().c_str());
		return tmpStr;
	}
	
	void Code::print(){
		std::cout << "\n\nTac Generation\n--------------\n";
		std::cout << "Label:\t\tOperator:\tArg1:\t\tArg2:\t\tResult\n";
		std::cout << "-----------------------------------------------------------------------\n";
		if(m_qList != NULL)
		{
		  m_qList->print();
		}
	}
	
	
